home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / storage / lmgr / multi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  10.9 KB  |  432 lines

  1. /*
  2.  * multi.c  -- multi level lock table manager
  3.  *
  4.  *  Standard multi-level lock manager as per the Gray paper
  5.  * (at least, that is what it is supposed to be).  We implement
  6.  * three levels -- RELN, PAGE, TUPLE.  Tuple is actually TID
  7.  * a physical record pointer.  It isn't an object id.
  8.  *
  9.  * NOTES:
  10.  *   (1) The lock.c module assumes that the caller here is doing
  11.  * two phase locking.
  12.  *
  13.  *
  14.  * Interface:
  15.  *    MultiLockReln(), MultiLockTuple(), InitMultiLockm();
  16.  *
  17.  *
  18.  * $Header: /private/postgres/src/storage/lmgr/RCS/multi.c,v 1.11 1991/08/29 23:52:03 mer Exp $
  19.  */
  20. #include <stdio.h>
  21. #include "storage/lmgr.h"
  22. #include "storage/multilev.h"
  23.  
  24. #include "utils/rel.h"
  25. #include "utils/log.h"
  26. #include "tmp/miscadmin.h"        /* MyDatabaseId */
  27.  
  28.  
  29. /*
  30.  * INTENT indicates to higher level that a lower level lock has been
  31.  * set.  For example, a write lock on a tuple conflicts with a write 
  32.  * lock on a relation.  This conflict is detected as a WRITE_INTENT/
  33.  * WRITE conflict between the tuple's intent lock and the relation's
  34.  * write lock.
  35.  */
  36. static
  37. int MultiConflicts[] = {
  38.   NULL,    
  39.   /* All reads and writes at any level conflict with a write lock */
  40.   (1 << WRITE_LOCK)|(1 << WRITE_INTENT)|(1 << READ_LOCK)|(1 << READ_INTENT),
  41.   /* read locks conflict with write locks at curr and lower levels */
  42.   (1 << WRITE_LOCK)| (1 << WRITE_INTENT),  
  43.   /* write intent locks */
  44.   (1 << READ_LOCK) | (1 << WRITE_LOCK),
  45.   /* read intent locks*/
  46.   (1 << WRITE_LOCK),
  47.   /* extend locks for archive storage manager conflict only w/extend locks */
  48.   (1 << EXTEND_LOCK)
  49. };
  50.  
  51. /*
  52.  * write locks have higher priority than read locks and extend locks.  May
  53.  * want to treat INTENT locks differently.
  54.  */
  55. static
  56. int MultiPrios[] = {
  57.   NULL,
  58.   2,
  59.   1,
  60.   2,
  61.   1,
  62.   1
  63. };
  64.  
  65. /* 
  66.  * Lock table identifier for this lock table.  The multi-level
  67.  * lock table is ONE lock table, not three.
  68.  */
  69. LockTableId MultiTableId = NULL;
  70. LockTableId ShortTermTableId = NULL;
  71.  
  72. /*
  73.  * Create the lock table described by MultiConflicts and Multiprio.
  74.  */
  75.  
  76. LockTableId
  77. InitMultiLevelLockm()
  78. {
  79.   int tableId;
  80.  
  81.   /* -----------------------
  82.    * If we're already initialized just return the table id.
  83.    * -----------------------
  84.    */
  85.   if (MultiTableId)
  86.     return MultiTableId;
  87.  
  88.   tableId = LockTabInit("LockTable", MultiConflicts, MultiPrios, 5);
  89.   MultiTableId = tableId;
  90.   if (! (MultiTableId)) {
  91.     elog(WARN,"InitMultiLockm: couldnt initialize lock table");
  92.   }
  93.   /* -----------------------
  94.    * No short term lock table for now.  -Jeff 15 July 1991
  95.    * 
  96.    * ShortTermTableId = LockTabRename(tableId);
  97.    * if (! (ShortTermTableId)) {
  98.    *   elog(WARN,"InitMultiLockm: couldnt rename lock table");
  99.    * }
  100.    * -----------------------
  101.    */
  102.   return MultiTableId;
  103. }
  104.  
  105. /*
  106.  * MultiLockReln -- lock a relation
  107.  *
  108.  * Returns: TRUE if the lock can be set, FALSE otherwise.
  109.  */
  110. bool
  111. MultiLockReln(linfo, lockt)
  112. LockInfo    linfo;
  113. LOCKT        lockt;
  114. {
  115.   LOCKTAG    tag;
  116.  
  117.   /* LOCKTAG has two bytes of padding, unfortunately.  The
  118.    * hash function will return miss if the padding bytes aren't
  119.    * zero'd.
  120.    */
  121.   bzero(&tag,sizeof(tag));
  122.   tag.relId = linfo->lRelId.relId;
  123.   tag.dbId = linfo->lRelId.dbId;
  124.   return(MultiAcquire(MultiTableId, &tag, lockt, RELN_LEVEL));
  125. }
  126.  
  127. /*
  128.  * MultiLockTuple -- Lock the TID associated with a tuple
  129.  *
  130.  * Returns: TRUE if lock is set, FALSE otherwise.
  131.  *
  132.  * Side Effects: causes intention level locks to be set
  133.  *     at the page and relation level.
  134.  */
  135. bool
  136. MultiLockTuple(linfo, tidPtr, lockt)
  137. LockInfo    linfo;
  138. ItemPointer    tidPtr;
  139. LOCKT        lockt;        
  140. {
  141.   LOCKTAG    tag;
  142.  
  143.   /* LOCKTAG has two bytes of padding, unfortunately.  The
  144.    * hash function will return miss if the padding bytes aren't
  145.    * zero'd.
  146.    */
  147.   bzero(&tag,sizeof(tag));
  148.  
  149.   tag.relId = linfo->lRelId.relId;
  150.   tag.dbId = linfo->lRelId.dbId;
  151.  
  152.   /* not locking any valid Tuple, just the page */
  153.   tag.tupleId = *tidPtr;
  154.   return(MultiAcquire(MultiTableId, &tag, lockt, TUPLE_LEVEL));
  155. }
  156.  
  157. /*
  158.  * same as above at page level
  159.  */
  160. bool
  161. MultiLockPage(linfo, tidPtr, lockt)
  162. LockInfo    linfo;
  163. ItemPointer    tidPtr;
  164. LOCKT        lockt;        
  165. {
  166.   LOCKTAG    tag;
  167.  
  168.   /* LOCKTAG has two bytes of padding, unfortunately.  The
  169.    * hash function will return miss if the padding bytes aren't
  170.    * zero'd.
  171.    */
  172.   bzero(&tag,sizeof(tag));
  173.  
  174.  
  175.   /* ----------------------------
  176.    * Now we want to set the page offset to be invalid 
  177.    * and lock the block.  There is some confusion here as to what
  178.    * a page is.  In Postgres a page is an 8k block, however this
  179.    * block may be partitioned into many subpages which are sometimes
  180.    * also called pages.  The term is overloaded, so don't be fooled
  181.    * when we say lock the page we mean the 8k block. -Jeff 16 July 1991
  182.    * ----------------------------
  183.    */
  184.   tag.relId = linfo->lRelId.relId;
  185.   tag.dbId = linfo->lRelId.dbId;
  186.   BlockIdCopy( ItemPointerBlockId(&tag.tupleId), ItemPointerBlockId(tidPtr) );
  187.   return(MultiAcquire(MultiTableId, &tag, lockt, PAGE_LEVEL));
  188. }
  189.  
  190. /*
  191.  * MultiAcquire -- acquire multi level lock at requested level
  192.  *
  193.  * Returns: TRUE if lock is set, FALSE if not
  194.  * Side Effects:
  195.  */
  196. bool
  197. MultiAcquire(tableId, tag, lockt, level)
  198. LockTableId        tableId;
  199. LOCKTAG        *tag;
  200. LOCK_LEVEL      level;
  201. LOCKT        lockt;
  202. {
  203.   LOCKT locks[N_LEVELS];
  204.   int    i,status;
  205.   LOCKTAG     xxTag, *tmpTag = &xxTag;
  206.   int    retStatus = TRUE;
  207.  
  208.   /*
  209.    * Three levels implemented.  If we set a low level (e.g. Tuple)
  210.    * lock, we must set INTENT locks on the higher levels.  The 
  211.    * intent lock detects conflicts between the low level lock
  212.    * and an existing high level lock.  For example, setting a
  213.    * write lock on a tuple in a relation is disallowed if there
  214.    * is an existing read lock on the entire relation.  The
  215.    * write lock would set a WRITE + INTENT lock on the relation
  216.    * and that lock would conflict with the read.
  217.    */
  218.   switch (level) {
  219.   case RELN_LEVEL:
  220.     locks[0] = lockt;
  221.     locks[1] = NO_LOCK;
  222.     locks[2] = NO_LOCK;
  223.     break;
  224.   case PAGE_LEVEL:
  225.     locks[0] = lockt + INTENT;
  226.     locks[1] = lockt;
  227.     locks[2] = NO_LOCK;
  228.     break;
  229.   case TUPLE_LEVEL:
  230.     locks[0] = lockt + INTENT;
  231.     locks[1] = lockt + INTENT;
  232.     locks[2] = lockt;
  233.     break;
  234.   default:
  235.     elog(WARN,"MultiAcquire: bad lock level");
  236.     return(FALSE);
  237.   }
  238.   
  239.   /*
  240.    * construct a new tag as we go. Always loop through all levels,
  241.    * but if we arent' seting a low level lock, locks[i] is set to
  242.    * NO_LOCK for the lower levels.  Always start from the highest
  243.    * level and go to the lowest level. 
  244.    */
  245.   bzero(tmpTag,sizeof(*tmpTag));
  246.   tmpTag->relId = tag->relId;
  247.   tmpTag->dbId = tag->dbId;
  248.  
  249.   for (i=0;i<N_LEVELS;i++) {
  250.     if (locks[i] != NO_LOCK) {
  251.       switch (i) {
  252.       case RELN_LEVEL:
  253.     /* -------------
  254.      * Set the block # and offset to invalid
  255.      * -------------
  256.      */
  257.     BlockIdSet(ItemPointerBlockId(&tmpTag->tupleId), InvalidBlockNumber);
  258.     PositionIdSetInvalid( ItemPointerPositionId(&(tmpTag->tupleId)) );
  259.     break;
  260.       case PAGE_LEVEL:
  261.     /* -------------
  262.      * Copy the block #, set the offset to invalid
  263.      * -------------
  264.      */
  265.     BlockIdCopy(ItemPointerBlockId(&tmpTag->tupleId),ItemPointerBlockId(&tag->tupleId));
  266.  
  267.     PositionIdSetInvalid(ItemPointerPositionId(&(tmpTag->tupleId)));
  268.     break;
  269.       case TUPLE_LEVEL:
  270.     /* --------------
  271.      * Copy the entire tuple id.
  272.      * --------------
  273.      */
  274.     ItemPointerCopy(&tmpTag->tupleId, &tag->tupleId);
  275.     break;
  276.       }
  277.  
  278.       status = LockAcquire(tableId, tmpTag, locks[i]);
  279.       if (! status) {
  280.     /* failed for some reason. Before returning we have
  281.      * to release all of the locks we just acquired.
  282.      * MultiRelease(xx,xx,xx, i) means release starting from
  283.      * the last level lock we successfully acquired
  284.      */
  285.     retStatus = FALSE;
  286.     (void) MultiRelease(tableId, tag, lockt, i);
  287.     /* now leave the loop.  Don't try for any more locks */
  288.     break;
  289.       }
  290.     }
  291.   }
  292.   return(retStatus);
  293. }
  294.  
  295. /* ------------------
  296.  * Release a page in the multi-level lock table
  297.  * ------------------
  298.  */
  299. bool
  300. MultiReleasePage(linfo, tidPtr, lockt)
  301. LockInfo    linfo;
  302. ItemPointer    tidPtr;
  303. LOCKT        lockt;        
  304. {
  305.   LOCKTAG tag;
  306.  
  307.   /* ------------------
  308.    * LOCKTAG has two bytes of padding, unfortunately.  The
  309.    * hash function will return miss if the padding bytes aren't
  310.    * zero'd.
  311.    * ------------------
  312.    */
  313.   bzero(&tag, sizeof(LOCKTAG));
  314.  
  315.   tag.relId = linfo->lRelId.relId;
  316.   tag.dbId = linfo->lRelId.dbId;
  317.   BlockIdCopy( ItemPointerBlockId(&tag.tupleId), ItemPointerBlockId(tidPtr) );
  318.  
  319.   return (MultiRelease(MultiTableId, &tag, lockt, PAGE_LEVEL));
  320. }
  321.  
  322. /* ------------------
  323.  * Release a relation in the multi-level lock table
  324.  * ------------------
  325.  */
  326. bool
  327. MultiReleaseReln(linfo, lockt)
  328. LockInfo    linfo;
  329. LOCKT        lockt;        
  330. {
  331.   LOCKTAG tag;
  332.  
  333.   /* ------------------
  334.    * LOCKTAG has two bytes of padding, unfortunately.  The
  335.    * hash function will return miss if the padding bytes aren't
  336.    * zero'd.
  337.    * ------------------
  338.    */
  339.   bzero(&tag, sizeof(LOCKTAG));
  340.   tag.relId = linfo->lRelId.relId;
  341.   tag.dbId = linfo->lRelId.dbId;
  342.  
  343.   return (MultiRelease(MultiTableId, &tag, lockt, RELN_LEVEL));
  344. }
  345.  
  346. /*
  347.  * MultiRelease -- release a multi-level lock
  348.  *
  349.  * Returns: TRUE if successful, FALSE otherwise.
  350.  */
  351. bool
  352. MultiRelease(tableId, tag, lockt, level)
  353. LockTableId        tableId;
  354. LOCKTAG        *tag;
  355. LOCK_LEVEL      level;
  356. LOCKT        lockt;
  357. {
  358.   LOCKT     locks[N_LEVELS];
  359.   int        i,status;
  360.   LOCKTAG     xxTag, *tmpTag = &xxTag;
  361.  
  362.   /* 
  363.    * same level scheme as MultiAcquire().
  364.    */
  365.   switch (level) {
  366.   case RELN_LEVEL:
  367.     locks[0] = lockt;
  368.     locks[1] = NO_LOCK;
  369.     locks[2] = NO_LOCK;
  370.     break;
  371.   case PAGE_LEVEL:
  372.     locks[0] = lockt + INTENT;
  373.     locks[1] = lockt;
  374.     locks[2] = NO_LOCK;
  375.     break;
  376.   case TUPLE_LEVEL:
  377.     locks[0] = lockt + INTENT;
  378.     locks[1] = lockt + INTENT;
  379.     locks[2] = lockt;
  380.     break;
  381.   default:
  382.     elog(WARN,"MultiRelease: bad lockt");
  383.   }
  384.   
  385.   /*
  386.    * again, construct the tag on the fly.  This time, however,
  387.    * we release the locks in the REVERSE order -- from lowest
  388.    * level to highest level.  
  389.    *
  390.    * Must zero out the tag to set padding byes to zero and ensure
  391.    * hashing consistency.
  392.    */
  393.   bzero(tmpTag,sizeof(*tmpTag));
  394.   tmpTag->relId = tag->relId;
  395.   tmpTag->dbId =  tag->dbId;
  396.  
  397.   for (i=(N_LEVELS-1); i>=0; i--) 
  398.   {
  399.     if (locks[i] != NO_LOCK) 
  400.     {
  401.       switch (i) 
  402.       {
  403.       case RELN_LEVEL:
  404.         /* -------------
  405.          * Set the block # and offset to invalid
  406.          * -------------
  407.          */
  408.         BlockIdSet(ItemPointerBlockId(&tmpTag->tupleId),InvalidBlockNumber);
  409.         PositionIdSetInvalid(ItemPointerPositionId(&tmpTag->tupleId));
  410.         break;
  411.       case PAGE_LEVEL:
  412.         /* -------------
  413.          * Copy the block #, set the offset to invalid
  414.          * These long macros cannot have newlines in them or else... 8-X
  415.          * -------------
  416.          */
  417.         BlockIdCopy(ItemPointerBlockId(&tmpTag->tupleId),ItemPointerBlockId(&tag->tupleId));
  418.   
  419.         PositionIdSetInvalid(ItemPointerPositionId(&(tmpTag->tupleId)));
  420.         break;
  421.       case TUPLE_LEVEL:
  422.         ItemPointerCopy(&tmpTag->tupleId, &tag->tupleId);
  423.         break;
  424.       }
  425.       status = LockRelease(tableId, tmpTag, locks[i]);
  426.       if (! status) {
  427.     elog(WARN,"MultiRelease: couldn't release after error");
  428.       }
  429.     }
  430.   }
  431. }
  432.